package com.junxonline.instant.admin.service.device.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.junxonline.instant.dao.entity.dto.ui.TreeSelectNodeDTO;
import com.junxonline.instant.dao.entity.model.device.Group;
import com.junxonline.instant.dao.entity.vo.device.GroupVO;
import com.junxonline.instant.dao.entity.vo.device.TerminalVO;
import com.junxonline.instant.dao.mapper.device.GroupMapper;
import com.junxonline.instant.admin.service.device.GroupService;
import com.junxonline.instant.common.annotation.DataScope;
import com.junxonline.instant.common.entity.common.CommonReqPage;
import com.junxonline.instant.common.entity.common.CommonRespPage;
import com.junxonline.instant.common.enumeration.AdminErrorEnum;
import com.junxonline.instant.common.exception.AdminBizException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 终端分组管理接口实现类
 *
 * @author JunX
 * @date 2021-09-29
 */
@Service
@Transactional
public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group> implements GroupService {

    @Autowired
    private GroupMapper groupMapper;

    /**
     * 查询终端分组下拉列表（TreeSelect）
     *
     * @param wrapper 条件查询器
     * @return List<TreeSelectNodeDTO>
     */
    @Override
    public List<TreeSelectNodeDTO> queryGroupTreeSelect(QueryWrapper<Group> wrapper) {
        List<TreeSelectNodeDTO> treeSelectNodes = new ArrayList<>();
        List<Group> groups = groupMapper.queryList(wrapper.isNull("t.parent_id"));
        for (Group group : groups) {
            List<Group> childrenGroups = groupMapper.queryChildren(group.getId());
            if (childrenGroups.size() > 0) {
                group.setChildren(childrenGroups);
            }
            treeSelectNodes.add(this.getTreeSelectTree(group));
        }
        return treeSelectNodes;
    }

    /**
     * 查询终端分组树（TreeSelect）
     *
     * @param vo 请求参数
     * @return List<TreeSelectNodeDTO>
     */
    @Override
    public List<TreeSelectNodeDTO> queryGroupTree(TerminalVO vo) {
        Long organizationId = vo.getOrganizationId();
        List<TreeSelectNodeDTO> treeSelectNodes = new ArrayList<>();
        List<Group> groups = groupMapper.queryList(new QueryWrapper<Group>().isNull("t.parent_id").eq("t.organization_id", organizationId));
        if (groups == null || groups.size() <= 0) {
            return treeSelectNodes;
        }
        for (Group group : groups) {
            List<Group> children = groupMapper.queryChildren(group.getId());
            if (children.size() > 0) {
                group.setChildren(children);
            }
            treeSelectNodes.add(this.getTreeSelectTree(group));
        }
        return treeSelectNodes;
    }

    /**
     * 查询上级分组树（TreeSelect）
     *
     * @param vo 请求参数
     * @return List<TreeSelectNodeDTO>
     */
    @Override
    @SuppressWarnings("unchecked")
    public List<TreeSelectNodeDTO> queryParentTree(GroupVO vo) {
        LambdaQueryWrapper<Group> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(vo.getOrganizationId() != null, Group::getOrganizationId, vo.getOrganizationId());
        wrapper.orderByAsc(Group::getSort);
        List<Group> groups = groupMapper.selectList(wrapper);
        return this.getTreeSelectTree(groups);
    }

    /**
     * 查询终端分组列表
     *
     * @param vo      请求参数
     * @param wrapper 条件查询器
     * @return List<Group>
     */
    @Override
    @DataScope
    public CommonRespPage<Group> queryList(CommonReqPage<GroupVO> vo, QueryWrapper<Group> wrapper) {
        wrapper.like(StrUtil.isNotBlank(vo.getQueryParams().getName()), "t.name", vo.getQueryParams().getName());
        wrapper.in(vo.getQueryParams().getOrganizationId() != null, "t.organization_id", vo.getQueryParams().getOrganizationId());
        List<Group> groups = groupMapper.queryList(wrapper);
        Page<Group> page = new Page<>();
        page.setRecords(this.getGroupTree(groups));
        page.setTotal(groups.size());
        return CommonRespPage.success(page, this.getParentGroupTreeId(groups));
    }

    /**
     * 查询终端分组
     *
     * @param id ID
     * @return Group
     */
    @Override
    public Group query(Long id) {
        Group group = groupMapper.selectById(id);
        Assert.notNull(group, AdminErrorEnum.DATA_IS_NOT_EXISTS.getMsg());
        return group;
    }

    /**
     * 新增终端分组
     *
     * @param group 请求参数
     */
    @Override
    public void add(Group group) {
        Integer count = groupMapper.selectCount(new LambdaQueryWrapper<Group>()
                .eq(Group::getOrganizationId, group.getOrganizationId())
                .eq(Group::getName, group.getName()));
        if (count > 0) {
            throw new AdminBizException(AdminErrorEnum.DATA_IS_EXISTS);
        }
        groupMapper.insert(group);
    }

    /**
     * 编辑终端分组
     *
     * @param group 请求参数
     */
    @Override
    public void edit(Group group) {
        Integer count = groupMapper.selectCount(new LambdaQueryWrapper<Group>()
                .ne(Group::getId, group.getId())
                .eq(Group::getOrganizationId, group.getOrganizationId())
                .eq(Group::getName, group.getName()));
        if (count > 0) {
            throw new AdminBizException(AdminErrorEnum.DATA_IS_EXISTS);
        }
        groupMapper.updateById(group);
    }

    /**
     * 删除终端分组
     *
     * @param ids 请求参数
     */
    @Override
    public void delete(List<Long> ids) {
        groupMapper.deleteBatchIds(ids);
    }

    /**
     * 生成父级分组树ID集合
     *
     * @param groups 终端分组集合
     * @return List<String>
     */
    private List<String> getParentGroupTreeId(List<Group> groups) {
        List<String> parentGroupIds = new ArrayList<>();
        for (Group group : groups) {
            List<Group> currentGroupParents = groups.stream().filter(g -> g.getId().equals(group.getParentId())).collect(Collectors.toList());
            if (currentGroupParents.size() <= 0) {
                parentGroupIds.add(group.getId().toString());
            }
        }
        return parentGroupIds;
    }

    /**
     * 递归生成分组树
     *
     * @param groups 终端分组集合
     * @return List<Group>
     */
    private List<Group> getGroupTree(List<Group> groups) {
        List<Group> menuList = new ArrayList<>();
        for (Group group : getParentGroupTree(groups)) {
            this.getChildrenGroupTree(group, groups);
            menuList.add(group);
        }
        return menuList;
    }

    /**
     * 生成父级分组树
     *
     * @param groups 终端分组集合
     * @return List<Group>
     */
    private List<Group> getParentGroupTree(List<Group> groups) {
        List<Group> parentGroups = new ArrayList<>();
        for (Group group : groups) {
            List<Group> currentGroupParents = groups.stream().filter(g -> g.getId().equals(group.getParentId())).collect(Collectors.toList());
            if (currentGroupParents.size() <= 0) {
                parentGroups.add(group);
            }
        }
        return parentGroups;
    }

    /**
     * 递归生成子分组树节点
     *
     * @param parentGroup 上级分组
     * @param groups      终端分组集合
     * @return Group
     */
    private Group getChildrenGroupTree(Group parentGroup, List<Group> groups) {
        List<Group> childrenParentGroups = new ArrayList<>();
        for (Group group : groups) {
            if (parentGroup.getId().equals(group.getParentId())) {
                childrenParentGroups.add(getChildrenGroupTree(group, groups));
            }
        }
        if (childrenParentGroups.size() > 0) {
            parentGroup.setChildren(childrenParentGroups);
        }
        return parentGroup;
    }

    /**
     * 递归生成TreeSelect树
     *
     * @param groups 终端分组集合
     * @return List<TreeSelectNodeDTO>
     */
    private List<TreeSelectNodeDTO> getTreeSelectTree(List<Group> groups) {
        List<TreeSelectNodeDTO> treeSelectNodeList = new ArrayList<>();
        for (TreeSelectNodeDTO node : getParentTreeSelectNode(groups)) {
            this.getChildrenTreeSelectNode(node, groups);
            treeSelectNodeList.add(node);
        }
        return treeSelectNodeList;
    }

    /**
     * 数据转为TreeSelectNode格式
     *
     * @param group 终端分组
     */
    private TreeSelectNodeDTO getTreeSelectTree(Group group) {
        TreeSelectNodeDTO node = new TreeSelectNodeDTO(group.getId(), group.getId(), group.getName());
        List<TreeSelectNodeDTO> childrenList = new ArrayList<>();
        // 递归子级
        if (group.getChildren() != null && group.getChildren().size() > 0) {
            for (Group children : group.getChildren()) {
                childrenList.add(this.getTreeSelectTree(children));
            }
        }
        if (childrenList.size() > 0) {
            node.setChildren(childrenList);
        }
        return node;
    }

    /**
     * 生成父级TreeSelect树
     *
     * @param groups 终端分组集合
     * @return List<TreeSelectNodeDTO>
     */
    private List<TreeSelectNodeDTO> getParentTreeSelectNode(List<Group> groups) {
        List<TreeSelectNodeDTO> parentNodes = new ArrayList<>();
        for (Group group : groups) {
            List<Group> currentGroupParents = groups.stream().filter(g -> g.getId().equals(group.getParentId())).collect(Collectors.toList());
            if (currentGroupParents.size() <= 0) {
                parentNodes.add(new TreeSelectNodeDTO(group.getId(), group.getId(), group.getName()));
            }
        }
        return parentNodes;
    }

    /**
     * 递归生成子TreeSelect树节点
     *
     * @param parentNode 上级节点
     * @param groups     终端分组集合
     * @return TreeSelectNodeDTO
     */
    private TreeSelectNodeDTO getChildrenTreeSelectNode(TreeSelectNodeDTO parentNode, List<Group> groups) {
        List<TreeSelectNodeDTO> childrenTreeSelectNodes = new ArrayList<>();
        for (Group group : groups) {
            if (parentNode.getKey().equals(group.getParentId())) {
                childrenTreeSelectNodes.add(getChildrenTreeSelectNode(new TreeSelectNodeDTO(group.getId(), group.getId(), group.getName()), groups));
            }
        }
        if (childrenTreeSelectNodes.size() > 0) {
            parentNode.setChildren(childrenTreeSelectNodes);
        }
        return parentNode;
    }

}
